/*
 * ListIterator.cpp
 *
 *  Created on: Apr 25, 2012
 *      Author: REZNIK
 */


#include "ListIterator.h"

#include "NodeHead.h"
#include "NodeTail.h"

using namespace cs236703_spring2012_hw2;

namespace cs236703_spring2012_hw2{

	ListIterator::ListIterator(
		LinkedListImpl* _list, Node* node, int version):
		list(_list), curr(node), time(version){ curr->AddRef(); }

	ListIterator::~ListIterator(){ curr->RemoveRef(); }

	void ListIterator::AddBefore(int value, bool immutable){
		Node* next=NULL;
		Node* prev=NULL;
		Node* newNode=NULL;
		checkVersion();
		if (dynamic_cast<NodeHead*>(curr) ||
				dynamic_cast<NodeTail*>(curr)){
			throw IllegalStateException();
		}
		if(dynamic_cast<NodeImpl*>(curr)->IsRemoved()){
			throw IllegalStateException();}
		if(dynamic_cast<NodeImpl*>(curr)->IsAdded()){
			throw IllegalStateException();}
		next = curr;
		prev = curr->GetPrev();
		newNode = list->getNewNode(value,immutable);
		prev->SetNext(newNode);
		next->SetPrev(newNode);
		newNode->SetNext(next);
		newNode->SetPrev(prev);
		dynamic_cast<NodeImpl*>(curr)->SetAdded();
		time = list->GetVersion();
	}


	void ListIterator::AddAfter(int value, bool immutable){
		Node* next=NULL;
		Node* prev=NULL;
		Node* newNode=NULL;
		checkVersion();
		if (dynamic_cast<NodeHead*>(curr) ||
				dynamic_cast<NodeTail*>(curr)){
			throw IllegalStateException();
		}
		if(dynamic_cast<NodeImpl*>(curr)->IsRemoved()){
			throw IllegalStateException();}
		if(dynamic_cast<NodeImpl*>(curr)->IsAdded()){
			throw IllegalStateException();}
		prev = curr;
		next = curr->GetNext();
		newNode = list->getNewNode(value,immutable);
		prev->SetNext(newNode);
		next->SetPrev(newNode);
		newNode->SetNext(next);
		newNode->SetPrev(prev);
		dynamic_cast<NodeImpl*>(curr)->SetAdded();
		time = list->GetVersion();
	}

	bool ListIterator::HasNext() const{
		bool tail(false);
		if(time != list->GetVersion()) return false;
		if (dynamic_cast<NodeTail*>(curr->GetNext())){
			tail = true;
		}
		if(dynamic_cast<NodeImpl*>(curr->GetPrev())->IsRemoved())
			tail = true;
		return !tail;
	}

	bool ListIterator::HasPrevious() const{
		bool head = false;
		if(time != list->GetVersion()) return false;
		if (dynamic_cast<NodeHead*>(curr->GetPrev())){
			head =true;
		}
		if(dynamic_cast<NodeImpl*>(curr->GetPrev())->IsRemoved())
			head = true;
		return !head;
	}

	int ListIterator::Next(){
		Node* temp = NULL;
		checkVersion();
		if(ListIterator::HasNext()){
			temp = curr->GetNext();
			curr->RemoveRef();
			curr = temp;
			curr->AddRef();
			dynamic_cast<NodeImpl*>(curr)->SetMoved();
		}else{
			throw NoSuchElementException();
		}
		return curr->GetValue();
	}

	int ListIterator::Previous(){
		Node* temp = NULL;
		checkVersion();
		if(ListIterator::HasPrevious()){
			temp = curr->GetPrev();
			curr->RemoveRef();
			curr = temp;
			curr->AddRef();
			dynamic_cast<NodeImpl*>(curr)->SetMoved();
		}else{
			throw NoSuchElementException();
		}
		return curr->GetValue();
	}


	void ListIterator::Remove(){
		Node* next=NULL;
		Node* prev=NULL;
		checkVersion();
		//Can't be tail. We start with head and never get to tail.
		if (list->isEmpty() || dynamic_cast<NodeHead*>(curr)){
			throw IllegalStateException();
		}
		if(dynamic_cast<NodeImpl*>(curr)->IsRemoved()){
			throw IllegalStateException();}
		if(dynamic_cast<NodeImpl*>(curr)->IsAdded()){
			throw IllegalStateException();}
		next = curr->GetNext();
		prev = curr->GetPrev();
		next->SetPrev(prev);
		prev->SetNext(next);
		list->removeNode(curr);
		time = list->GetVersion();
		//won't delete till move iterator
		dynamic_cast<NodeImpl*>(curr)->SetRemoved();
	}
	// Set the value of the pointed element.
	void ListIterator::Set(int val){
		checkVersion();
		if(dynamic_cast<NodeImpl*>(curr)->IsRemoved()){
			throw IllegalStateException();}
		if(dynamic_cast<NodeImpl*>(curr)->IsAdded()){
			throw IllegalStateException();}
		curr->SetValue(val);
	}
	// Get the value of the pointed element.
	int ListIterator::Get() const{
		if(dynamic_cast<NodeImpl*>(curr)->IsRemoved()){
			throw IllegalStateException();}
		if(dynamic_cast<NodeImpl*>(curr)->IsAdded()){
			throw IllegalStateException();}
		return curr->GetValue();
	}


}

